﻿using System.Reflection;
using System.Windows.Forms;
using System.WindowsCe.Mvp.DependencyInjection;
using System.WindowsCe.Mvp.Presenters;
using System.WindowsCe.Mvp.Views;

namespace System.WindowsCe.Mvp.Navigation
{
    public static class ApplicationController
    {
        private static INavigationWorkflow _navigationWorkflow;

        public static void Register(INavigationWorkflow navigationWorkflow)
        {
            if (navigationWorkflow == null)
            {
                throw new ArgumentNullException("navigationWorkflow");
            }
            _navigationWorkflow = navigationWorkflow;
        }

        public static void NavigateTo(Type viewInterface, Type contextModelType, object argument)
        {
            if (_navigationWorkflow == null)
            {
                throw new InvalidOperationException("Необходимо сначала установить INavigationWorkflow.");
            }

            var view = GetView(viewInterface, contextModelType, argument);
            _navigationWorkflow.NavigateTo(view);
        }

        public static void NavigateTo<TViewInterface, TContextModel>()
            where TViewInterface : IView
            where TContextModel : class
        {
            NavigateTo<TViewInterface, TContextModel>(null);
        }

        public static void NavigateTo<TViewInterface, TContextModel>(TContextModel argument)
            where TViewInterface : IView
            where TContextModel : class
        {
            if (_navigationWorkflow == null)
            {
                throw new InvalidOperationException("Необходимо сначала установить INavigationWorkflow.");
            }

            TViewInterface view = GetView<TViewInterface, TContextModel>(argument);
            _navigationWorkflow.NavigateTo(view);
        }

        public static DialogResult NavigateDialog(Type viewInterface, Type contextModelType, object argument)
        {
            if (_navigationWorkflow == null)
            {
                throw new InvalidOperationException("Необходимо сначала установить INavigationWorkflow.");
            }

            var view = GetView(viewInterface, contextModelType, argument);
            return _navigationWorkflow.NavigateDialog(view);
        }

        public static DialogResult NavigateDialog<TViewInterface, TContextModel>()
            where TViewInterface : IView
            where TContextModel : class
        {
            return NavigateDialog<TViewInterface, TContextModel>(null);
        }

        public static DialogResult NavigateDialog<TViewInterface, TContextModel>(TContextModel argument)
            where TViewInterface : IView
            where TContextModel : class
        {
            if (_navigationWorkflow == null)
            {
                throw new InvalidOperationException("Необходимо сначала установить INavigationWorkflow.");
            }

            var view = GetView<TViewInterface, TContextModel>(argument);
            return _navigationWorkflow.NavigateDialog(view);
        }

        public static void SetupInternalView<TViewInterface, TContextModel>(IContainView containView)
            where TViewInterface : IView
            where TContextModel : class
        {
            SetupInternalView<TViewInterface, TContextModel>(containView, null);
        }

        public static void SetupInternalView<TViewInterface, TContextModel>(IContainView containView, TContextModel argument)
            where TViewInterface : IView
            where TContextModel : class
        {
            var view = GetView<TViewInterface, TContextModel>(argument);
            containView.SetView(view);
        }

        public static void SetupInternalView(IContainView containView, Type viewInterface, object argument)
        {
            if (argument == null)
            {
                throw new ArgumentNullException("argument");
            }
            SetupInternalView(containView, viewInterface, argument.GetType(), null);
        }

        public static void SetupInternalView(IContainView containView, Type viewInterface, Type contextModelType, object argument)
        {
            var view = GetView(viewInterface, contextModelType, argument);
            containView.SetView(view);
        }

        public static TViewInterface GetView<TViewInterface, TContextModel>(TContextModel argument)
            where TViewInterface : IView
            where TContextModel : class
        {
            IPresenter<TViewInterface, TContextModel> presenter = DependencyResolver.Current.Resolve<IPresenter<TViewInterface, TContextModel>>();
            presenter.SetContextModel(argument);
            var view = presenter.View;
            view.Presenter = presenter;

            return view;
        }

        public static IView GetView(Type viewInterface, Type contextModelType, object argument)
        {
            Type presenterType = typeof(IPresenter<,>).MakeGenericType(viewInterface, contextModelType);

            var presenter = (IPresenter)DependencyResolver.Current.Resolve(presenterType);

            MethodInfo methodInfo = presenterType.GetMethod("SetContextModel", new[] { contextModelType });
            methodInfo.Invoke(presenter, new[] { argument });

            var view = presenter.View;
            view.Presenter = presenter;

            return view;
        }
    }
}